package com.bigdata.utils;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

//import javax.persistence.FetchType;
//import javax.persistence.ManyToMany;
//import javax.persistence.ManyToOne;
//import javax.persistence.OneToMany;


public class ReflectUtil {
    /**
     * 获取字段值
     *
     * @param @param  m
     * @param @param  fieldName
     * @param @return 设定文件
     * @return Object    返回类型
     * @throws
     * @author lly
     * @Title: getFieldValue
     * @Description: TODO(这里用一句话描述这个方法的作用)
     */
    public static <M> Object getFieldValue(M m, String fieldName) {
        Object value = null;
        try {
            Field field = m.getClass().getDeclaredField(fieldName);
            if (field != null) {
                field.setAccessible(true);
                value = field.get(m);
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 得到某个对象的公共属性
     *
     * @param owner, fieldName
     * @return 该属性对象
     * @throws Exception
     */
    public static Object getProperty(Object owner, String fieldName) throws Exception {
        Class ownerClass = owner.getClass();
        Field field = ownerClass.getField(fieldName);
        Object property = field.get(owner);
        return property;
    }

    /**
     * 得到某类的静态公共属性    [没有多大用处，自我感觉]
     *
     * @param className 类名
     * @param fieldName 属性名
     * @return 该属性对象
     * @throws Exception
     */
    public static Object getStaticProperty(String className, String fieldName) throws Exception {
        Class ownerClass = Class.forName(className);
        Object obj = ownerClass.newInstance();
        Field field = ownerClass.getField(fieldName);
        field.set(obj, "miao  peng");
        Object property = field.get(obj);
        return property;
    }


    /**
     * 利用反射调用方法（根据实例对象）
     *
     * @param owner      实例对象
     * @param methodName 方法名
     * @param argsType   参数类型
     * @param argsValue  参数值
     * @return 方法的返回值
     * @throws Exception
     */
    public static Object invokeMethod(Object owner, String methodName, Class[] argsType, Object[] argsValue) throws Exception {
        Class ownerClass = owner.getClass();
        Method method = ownerClass.getDeclaredMethod(methodName, argsType);
        method.setAccessible(true);

        return method.invoke(owner, argsValue);
    }

    /**
     * 利用反射调用方法（根据类名）
     *
     * @param className  类名
     * @param methodName 方法名
     * @param argsType   参数类型
     * @param argsValue  参数值
     * @return
     * @throws Exception
     */
    public static Object invokeMethod(String className, String methodName, Class[] argsType, Object[] argsValue) throws Exception {
        Class ownerClass = Class.forName(className);
        Object owner = ownerClass.newInstance();
        Method method = ownerClass.getDeclaredMethod(methodName, argsType);
        method.setAccessible(true);
        return method.invoke(owner, argsValue);
    }

    /**
     * 利用java反射和构造方法生成实例
     *
     * @param className 类名
     * @param argsType  参数类型
     * @param argsValue 参数值
     * @return
     * @throws Exception
     */
    public static Object newInstance(String className, Class[] argsType, Object[] argsValue) throws Exception {
        Class newoneClass = Class.forName(className);
        Constructor cons = newoneClass.getConstructor(argsType);
        return cons.newInstance(argsValue);
    }

    /**
     * 是不是某个类的实例
     *
     * @param obj 实例
     * @param cls 类
     * @return 如果 obj 是cls类的实例，则返回 true
     */
    public static boolean isInstance(Object obj, Class cls) {
        return cls.isInstance(obj);
    }

    /**
     * 得到数组中的某个元素
     *
     * @param array 数组
     * @param index 索引
     * @return 返回指定数组对象中索引组件的值
     */
    public static Object getByArray(Object array, int index) {
        return Array.get(array, index);
    }

    /**
     * 获取class的 包括父类的
     *
     * @param clazz
     * @return
     */
    public static Field[] getClassFields(Class<?> clazz) {
        List<Field> list = new ArrayList<Field>();
        Field[] fields;
        do {
            fields = clazz.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                list.add(fields[i]);
            }
            clazz = clazz.getSuperclass();
        } while (clazz != Object.class && clazz != null);
        return list.toArray(fields);
    }

    /**
     * 字段名不区分大小写
     * 性能比getFieldValue低
     *
     * @param m
     * @param fieldName
     * @return
     */
    public static <M> Object getFieldValueNoCaseSensitive(M m, String fieldName) {
        Object value = null;
        try {
            Field[] fields = m.getClass().getDeclaredFields();
            Field f = null;
            for (Field f1 : fields) {
                if (f1.getName().toLowerCase().equals(fieldName.toLowerCase())) {
                    f = f1;
                    break;
                }
            }
            if (f != null)
                value = getFieldValue(m, f.getName());
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return value;
    }

    public static <M> void setFieldValue(M m, String fieldName,
                                         Object fieldValue) {
        try {
            Field[] fields = m.getClass().getDeclaredFields();
            if (fields != null) {
                for (Field f : fields) {
                    f.setAccessible(true);
                    if (f.getName().toLowerCase()
                            .equals(fieldName.trim().toLowerCase())) {
                        f.set(m, fieldValue);
                    }
                }
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static Class<?> forName(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            return null;
        }
    }

    /**
     * 根据对象，返回一个class对象，用于获取方法
     */
    public static Class<?> getClass(Object obj) {
        try {
            return Class.forName(obj.getClass().getName());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据对象，获取某个方法
     *
     * @param obj            对象
     * @param methodName     方法名
     * @param parameterTypes 该方法需传的参数类型，如果不需传参，则不传
     */
    public static Method getMethod(Object obj, String methodName,
                                   Class<?>... parameterTypes) {
        try {
            Method method = getClass(obj).getDeclaredMethod(methodName,
                    parameterTypes);
            method.setAccessible(true);
            return method;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Method getMethod(Class<?> cls, String methodName,
                                   Class<?>... parameterTypes) {
        try {
            Method method = cls.getDeclaredMethod(methodName, parameterTypes);
            method.setAccessible(true);
            return method;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 直接传入对象、方法名、参数，即可使用该对象的隐藏方法
     *
     * @param obj
     * @param methodName
     * @param parameter
     */
    public static Object invoke(Object obj, String methodName,
                                Object... parameter) {
        Class<?>[] parameterTypes = new Class<?>[parameter.length];
        for (int i = 0; i < parameterTypes.length; i++) {
            parameterTypes[i] = parameter[i].getClass();
        }
        try {
            return getMethod(obj, methodName, parameterTypes).invoke(obj,
                    parameter);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 直接传入类名、方法名、参数，即可使用该对象的隐藏静态方法
     *
     * @param cls
     * @param methodName
     * @param parameter
     */
    public static Object invoke(Class<?> cls, String methodName,
                                Object... parameter) {
        Class<?>[] parameterTypes = new Class<?>[parameter.length];
        for (int i = 0; i < parameterTypes.length; i++) {
            parameterTypes[i] = parameter[i].getClass();
        }
        try {
            return getMethod(cls, methodName, parameterTypes).invoke(null,
                    parameter);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


}
